<template>
  <div class="fetching-wrap">
    <!-- @slot default 默认插槽
    @binding {any} data
    @binding {Response} response
    @binding {boolean} loading
    -->
    <slot
      :data="data"
      :response="response"
      :loading="loading"
    />
    <component
      :is="useCardStyle ? 'el-card':'div'"
      :class="useCardStyle ? 'content':''"
    >
      <!-- @slot content 内容插槽
      @binding {any} data
      @binding {Response} response
      @binding {boolean} loading
       -->
      <slot
        name="content"
        :data="data"
        :response="response"
        :loading="loading"
      />
      <div
        v-if="usePagination"
        class="pagination-bar"
      >
        <!-- @slot pagepreend 在分页元素之前的插槽-->
        <slot name="pageprepend" />
        <Pagination
          :current-page="pager.page"
          :page-sizes="pageSizes"
          :page-size="defaultPageSize"
          layout="total, sizes, prev, pager, next, jumper"
          :total="pager.total"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
        />
      </div>
    </component>
  </div>
</template>
<script>
import { Pagination, Card } from 'element-ui'
import _ from 'lodash'

const REQUEST_KEY_VALUE_MAP = {
  page: 'page',
  size: 'size'
}

const RESPONSE_KEY_VALUE_MAP = {
  data: 'data',
  total: 'total'
}

/**
 * 用于通过请求获取数据
 * @displayName FetchPaging
 */
export default {
  name: 'FetchPaging',
  components: {
    Pagination,
    Card
  },
  props: {
    /**
     * 是否启用卡片样式
     */
    useCardStyle: {
      type: Boolean,
      default: true
    },
    /**
     * 是否开启分页
     */
    usePagination: {
      type: Boolean,
      default: true
    },
    /**
     * 是否Mounted就执行Fetch方法 ,
     * false:等待上层组件手动调用
     */
    immediateFetch: {
      type: Boolean,
      default: true
    },
    /**
     * http异步请求，用于获取数据的方法
     */
    request: {
      type: Function,
      // default: () => new Promise()
    },
    /**
     * http异步请求前的钩子函数，可以通过该钩子修改提交的参数。
     */
    beforeRequest: {
      type: Function
    },
    /**
     * http 异步请求后的钩子函数，可以通过该钩子修改获取后的数据。
     */
    afterRequest: {
      type: Function
    },
    /**
     * 调用fetch方法发生错误时，调用requestError
     */
    requestError: {
      type: Function,
      default() {
        return () => {}
      }
    },
    /**
     * 关于requestKeyValue的映射
     * @default: { page:"page" , pagesize:"page_size" }
     */
    requestKeyValueMap: {
      type: Object,
      default() {
        return { ...REQUEST_KEY_VALUE_MAP }
      }
    },
    /**
     * 关于response结果值的映射
     * 用来标识response结果中data的Key,数据总量的Key
     * @default: {data:"data.data" , "total":"data.total"}
     */
    responseKeyValueMap: {
      type: Object,
      default() {
        return {
          ...RESPONSE_KEY_VALUE_MAP
        }
      }
    },
    defaultPageSize: {
      type: Number,
      default: 20
    },
    pageSizes: {
      type: Array,
      default() {
        return [20, 50, 100, 200]
      }
    }
  },
  data() {
    return {
      pager: {
        page: 1,
        total: 0,
        size: this.defaultPageSize
      },
      data: [],
      response: {},
      loading: false
    }
  },
  computed: {
    requestKeyMap() {
      return {
        ...REQUEST_KEY_VALUE_MAP,
        ...this.requestKeyValueMap
      }
    },
    responseKeyMap() {
      return {
        ...RESPONSE_KEY_VALUE_MAP,
        ...this.responseKeyValueMap
      }
    }
  },
  mounted() {
    if (this.immediateFetch) {
      this.fetch()
    }
  },
  methods: {
    /**
     * 调用请求的方法。
     * 通过上层组件通过调用beforeRequest,afterRequest修改数据
     * @public
     */
    async fetch() {
      let pageParams = {
        [this.requestKeyMap.page]: this.pager.page,
        [this.requestKeyMap.size]: this.pager.size
      }
      if (!this.usePagination) {
        pageParams = {}
      }
      let requestPromise = Promise.resolve({ ...pageParams })
      if (_.isFunction(this.beforeRequest)) {
        const p = this.beforeRequest({ ...pageParams })
        if (!(p instanceof Promise)) {
          requestPromise = Promise.resolve(p)
        }
      }
      const params = await requestPromise
      try {
        this.$emit('on-before-request')
        this.loading = true
        const response = await this.request(params)
        this.response = response
        let afterResultPromise = Promise.resolve(response)
        if (_.isFunction(this.afterRequest)) {
          const afterResult = this.afterRequest(response)
          if (!(afterResult instanceof Promise)) {
            afterResultPromise = Promise.resolve(afterResult)
          }
        }
        const result = await afterResultPromise
        console.log(result)
        if (this.usePagination) {
          this.pager.total = _.get(result, this.responseKeyMap.total)
        }
        this.data = _.get(result, this.responseKeyMap.data)
        this.result = result
        /**
         * @property {Response} response
         */
        this.$emit('on-after-request', response)
      } catch (e) {
        this.requestError(e)
      } finally {
        this.loading = false
      }
    },

    /**
     * 将页面重置为1，
     * 重新调用请求
     * @public
     */
    refetch() {
      this.pager.page = 1
      return this.fetch()
    },

    /**
     * 修改pagination size,重新发起请求
     */
    handleSizeChange(val) {
      this.pager.size = val
      this.refetch()
    },
    /**
     * 修改当前页码，重新发起请求
     */
    handleCurrentChange(val) {
      this.pager.page = val
      this.fetch()
    }
  }
}
</script>
<style scoped>
.pagination-bar {
  margin-top: 10px;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  margin-right: 5px;
}
.content {
  margin: 0 20px 20px;
}
</style>
